#import "RNEditListItemCell.h"
#import "RNConstants.h"
#import "RNListItem.h"
#import "NSBezierPath+MCAdditions.h"
#import "RNCancelButtonCell.h"
#import "NSCell+SRAdditions.h"
#import "RNStepperCell.h"

@interface RNEditListItemCell (RNEditListItemCellPrivateMethods)
-(void)initializeState_;
@end


static NSUInteger const elementPadding = 10;
static NSUInteger const minimumTitleWidth = 30;
static NSUInteger const tagElementPadding = 5;
static NSUInteger const tagHeight = 16;
static NSUInteger const tagBezelCornerRadius = 8;

static NSGradient *tagsGradient, *tagsGradientHighlighted;
static NSColor *tagsBorderColor, *tagsTextColorHighlighted, *tagsTextColor;
static NSColor *titleTextColor;

@implementation RNEditListItemCell

@synthesize count = count_;
@synthesize complete = complete_;
@synthesize notes = notes_;
@synthesize tags = tags_;
@synthesize favorite = favorite_;
@synthesize list = list_;
@synthesize tagAttributes = tagAttributes_;
@synthesize mouseIsHoveringOverTitle = mouseIsHoveringOverTitle_;
@synthesize mouseIsHoveringOverCancel = mouseIsHoveringOverCancel_;
@synthesize titleAttributesNormal = titleAttributesNormal_;
@synthesize titleAttributesHover = titleAttributesHover_;
@synthesize countAttributes = countAttributes_;
@synthesize cancelButton = cancelButton_;
@synthesize stepperCell = stepperCell_;

+(void)initialize {
    tagsGradient = [[NSGradient alloc] initWithStartingColor:[NSColor whiteColor] endingColor:[NSColor colorWithCalibratedRed:0.818 green:0.825 blue:0.853 alpha:1.000]];
    tagsGradientHighlighted = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedRed:0.958 green:0.973 blue:0.998 alpha:1.000] endingColor:[NSColor colorWithCalibratedRed:0.787 green:0.825 blue:0.880 alpha:1.000]];
    tagsBorderColor = [NSColor colorWithCalibratedWhite:0.663 alpha:1.000];
    tagsTextColorHighlighted = [NSColor colorWithCalibratedRed:0.402 green:0.409 blue:0.460 alpha:1.000];
    tagsTextColor = [NSColor colorWithCalibratedRed:0.471 green:0.477 blue:0.520 alpha:1.000];
    titleTextColor = [NSColor blackColor];
}

+ (BOOL)prefersTrackingUntilMouseUp {
    return YES;
}

-(id)initTextCell:(NSString *)theString {
    if (!(self = [super initTextCell:theString]))
        return nil;
        
    [self initializeState_];
    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder {
    if (!(self = [super initWithCoder:aDecoder]))
        return nil;
    
    [self initializeState_];    
    return self;
}

-(id)copyWithZone:(NSZone *)zone {
    RNEditListItemCell *copy = [super copyWithZone:zone];
    
    copy->cancelButton_ = nil;
    copy->stepperCell_ = nil;
    [copy initializeState_];

    return copy;
}

-(void)initializeState_ {
    [self setLineBreakMode:NSLineBreakByTruncatingTail];
    [self setCancelButton:[[RNCancelButtonCell alloc] initTextCell:@""]];
    [[self cancelButton] setAction:@selector(deleteListItemFromCancelButtonCell:)];
    [self setAction:@selector(selectListFromEditListItemCell:)];
    
    [self setStepperCell:[[RNStepperCell alloc] initTextCell:@""]];
    [[self stepperCell] setSendsActionOnEndEditing:YES];
    [[self stepperCell] setFontSize:11.0f];
    [[self stepperCell] setTextColor:[NSColor colorWithCalibratedRed:0.402 green:0.410 blue:0.467 alpha:1.000]];
    [[self stepperCell] setArrowColor:[NSColor colorWithCalibratedRed:0.500 green:0.510 blue:0.582 alpha:1.000]];
    [[self stepperCell] setArrowPressedColor:[NSColor colorWithCalibratedRed:0.316 green:0.331 blue:0.375 alpha:1.000]];
}

//+(NSSet *)keyPathsForValuesAffectingObjectValue {
//    return [NSSet setWithObjects:@"title", @"count", @"complete", @"notes", @"tags", nil];
//}

-(NSArray *)keys {
    return [NSArray arrayWithObjects:@"title", @"count", nil];
}

+(NSSet *)keyPathsForValuesAffectingObjectValue {
    return [NSSet setWithObject:@"count"];
}

- (id)objectValue {
    return [self dictionaryWithValuesForKeys:[self keys]];
}

-(void)setObjectValue:(id)obj {
    if (![obj isKindOfClass:[NSDictionary class]])
        return;
    [self setValuesForKeysWithDictionary:obj];
    [super setObjectValue:[obj valueForKeyPath:@"list.title"]];
}

-(NSDictionary *)titleAttributesNormal {
    if (!titleAttributesNormal_) {
        NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
        [attributes setValue:[NSFont systemFontOfSize:12.0f] forKey:NSFontAttributeName];
        [attributes setValue:[NSColor colorWithCalibratedWhite:0.35f alpha:1.0f] forKey:NSForegroundColorAttributeName];
        titleAttributesNormal_ = (NSDictionary *)attributes;
    }
    return titleAttributesNormal_;
}

-(NSDictionary *)titleAttributesHover {
    if (!titleAttributesHover_) {
        NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
        [attributes setValue:[NSFont systemFontOfSize:12.0f] forKey:NSFontAttributeName];
        [attributes setValue:[NSColor colorWithCalibratedWhite:0.35f alpha:1.0f] forKey:NSForegroundColorAttributeName];
        [attributes setValue:[NSNumber numberWithInteger:NSUnderlineStyleSingle | NSUnderlinePatternSolid] forKey:NSUnderlineStyleAttributeName];
        titleAttributesHover_ = (NSDictionary *)attributes;
    }
    return titleAttributesHover_;
}

-(NSDictionary *)countAttributes {
    if (!countAttributes_) {
        NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
        [attributes setValue:[NSFont systemFontOfSize:11.0f] forKey:NSFontAttributeName];
        [attributes setValue:[NSColor colorWithCalibratedWhite:0.35f alpha:1.0f] forKey:NSForegroundColorAttributeName];
        countAttributes_ = (NSDictionary *)attributes;
    }
    return countAttributes_;
}

-(NSDictionary *)tagAttributes {
    if (!tagAttributes_) {
        NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
        [attributes setValue:[NSFont systemFontOfSize:11.0f] forKey:NSFontAttributeName];
//        [attributes setValue:[NSColor colorWithCalibratedWhite:0.35f alpha:1.0f] forKey:NSForegroundColorAttributeName];
        countAttributes_ = (NSDictionary *)attributes;
    }
    return tagAttributes_;
}


#pragma mark -
#pragma mark Cell Behavior

-(BOOL)isSelectable {
    return NO;
}


#pragma mark -
#pragma mark Drawing

-(void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {     
    // Draw tags
//    [self drawTagsInRect:[self tagsRectForBounds:cellFrame]];
    
    // Draw cancel button
    [[self cancelButton] drawWithFrame:[self cancelButtonRectForBounds:cellFrame] inView:controlView];
    
//    // Draw count text
//    [[self countAttributedString] drawInRect:[self countRectForBounds:cellFrame]];
    
    // Draw stepper
    [[self stepperCell] setIntegerValue:[[self count] integerValue]];
    [[self stepperCell] drawWithFrame:[self stepperRectForBounds:cellFrame] inView:controlView];

    // Draw Text
    [[self attributedStringValue] drawInRect:[self titleRectForBounds:cellFrame]];
}

- (NSAttributedString *)attributedStringValue {
    return [[NSAttributedString alloc] initWithString:[self stringValue] attributes:([self mouseIsHoveringOverTitle] ? [self titleAttributesHover] : [self titleAttributesNormal])];
}

-(NSAttributedString *)countAttributedString {
    return [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%i", [[self count] integerValue]] attributes:[self countAttributes]];
}

-(void)drawTagsInRect:(NSRect)tagRect {
//    if (![self tags])
//        return;
//    NSPoint currentTextPoint = NSMakePoint(NSMinX(tagRect) + (tagPadding / 2), NSMinY(tagRect) + 2.0f);
//    NSRect bezelRect = tagRect;
//    NSGradient *currentGradient = nil;
//    if ([[self complete] boolValue])
//        currentGradient = [self isHighlighted] ? tagsGradientCompleteHighlighted : tagsGradientComplete;
//    else
//        currentGradient = [self isHighlighted] ? tagsGradientHighlighted : tagsGradient;
//    NSColor *textColor = [self isHighlighted] ? tagsTextColorHighlighted : tagsTextColor;
//    NSColor *borderColor = nil;
//    if ([[self complete] boolValue])
//        borderColor = [self isHighlighted] ? tagsBorderColorCompletedHighlighted : tagsBorderColorCompleted;
//    else
//        borderColor = [self isHighlighted] ? tagsBorderColorHighlighted : tagsBorderColor;
//    NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithDictionary:[self tagAttributes]];
//    [attributes setValue:textColor forKey:NSForegroundColorAttributeName];
//    for (NSString *tag in [self tags]) {
//        NSAttributedString *attributedTag = [[NSAttributedString alloc] initWithString:tag attributes:attributes];
//        CGFloat tagWidth = [attributedTag size].width;
//        bezelRect.size.width = tagWidth + tagPadding;
//        NSBezierPath *bezelPath = [NSBezierPath bezierPathWithRoundedRect:bezelRect xRadius:tagBezelCornerRadius yRadius:tagBezelCornerRadius];
//        [currentGradient drawInBezierPath:bezelPath angle:90];
//        [borderColor setStroke];
//        [bezelPath stroke];
//        [attributedTag drawAtPoint:currentTextPoint];
//        bezelRect.origin.x += tagWidth + tagPadding + tagElementPadding;
//        currentTextPoint.x += tagWidth + tagPadding + tagElementPadding;
//    }
}

-(NSRect)stepperRectForBounds:(NSRect)cellFrame {
    NSRect stepperFrame = cellFrame;
    stepperFrame.origin.x = NSMaxX([self cancelButtonRectForBounds:cellFrame]) + RNGenericCellElementPadding;
    stepperFrame.size = NSMakeSize(RNStepperCellWidth, RNStepperCellWidth);
    stepperFrame.origin.y += floor(NSMidY(cellFrame) - NSMidY(stepperFrame));
    return stepperFrame;
}

-(NSRect)countRectForBounds:(NSRect)cellFrame {
    NSRect countFrame = cellFrame;
    countFrame.origin.x += RNGenericCellEndPadding + RNCancelButtonLength + RNGenericCellElementPadding;
    countFrame.size = [[self countAttributedString] size];
    countFrame.origin.y += NSMidY(cellFrame) - NSMidY(countFrame);
    return countFrame;
}

-(NSRect)titleRectForBounds:(NSRect)cellFrame {
    NSRect titleFrame = cellFrame;
//    titleFrame.origin.x += RNGenericCellEndPadding + RNCancelButtonLength + RNCountTextWidth + (2 * RNGenericCellElementPadding);
    titleFrame.origin.x  = NSMaxX([self stepperRectForBounds:cellFrame]) + RNGenericCellElementPadding;
    titleFrame.size = [[self attributedStringValue] size];
    titleFrame.size.width = fmin(NSWidth(titleFrame), NSWidth(cellFrame) - (2 * RNGenericCellEndPadding));
    titleFrame.origin.y += NSMidY(cellFrame) - NSMidY(titleFrame);
    return titleFrame;
}

-(NSRect)tagsRectForBounds:(NSRect)cellFrame {
//    if (![self tags])
//        return NSZeroRect;
//    CGFloat totalWidth = 0;
//    for (NSString *tag in [self tags]) {
//        NSAttributedString *tagString = [[NSAttributedString alloc] initWithString:tag attributes:[self tagAttributes]];
//        totalWidth += [tagString size].width;
//        totalWidth += tagPadding;
//    }
//    totalWidth += ([[self tags] count] - 1) * tagElementPadding;
//    CGFloat originX = NSMaxX(cellFrame) - RNGenericCellEndPadding - totalWidth;
//    if ([self notes])
//        originX = NSMinX([self notesRectForBounds:cellFrame]) - RNGenericCellElementPadding - totalWidth;
//    else if ([[self favorite] boolValue])
//        originX = NSMinX([self favoriteRectForBounds:cellFrame]) - RNGenericCellElementPadding - totalWidth;
//    CGFloat originY = NSMinY(cellFrame) + (NSHeight(cellFrame) - tagHeight) / 2;
//    return NSMakeRect(originX, originY, totalWidth, tagHeight);
    return cellFrame;
}

-(NSRect)cancelButtonRectForBounds:(NSRect)cellFrame {
    NSRect cancelRect = cellFrame;
    cancelRect.origin.x += RNGenericCellEndPadding;
    cancelRect.origin.y = NSMinY(cellFrame) + RNCancelButtonUpperPadding;
    cancelRect.size = NSMakeSize(RNCancelButtonLength, RNCancelButtonLength);
    return cancelRect;
}

- (NSColor *)highlightColorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
    return nil;
}


#pragma mark -
#pragma mark Event-handling

typedef enum {
    RNTrackingNone,
    RNTrackingTitle,
    RNTrackingCancelButton
} RNTrackingType;

static NSString *trackingTypeKey = @"trackingTypeKey";

- (void)addTrackingAreasForView:(NSView *)controlView inRect:(NSRect)cellFrame withUserInfo:(NSDictionary *)userInfo mouseLocation:(NSPoint)currentPoint {
    NSRect titleFrame = [self titleRectForBounds:cellFrame];
    NSTrackingAreaOptions options = NSTrackingEnabledDuringMouseDrag | NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways;
    NSMutableDictionary *cellUserInfo = [NSMutableDictionary dictionaryWithDictionary:userInfo];
    [cellUserInfo setValue:[NSNumber numberWithInteger:RNTrackingTitle] forKey:trackingTypeKey];
    NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect:titleFrame options:options owner:controlView userInfo:cellUserInfo];
    [controlView addTrackingArea:area];
    
    cellUserInfo = [NSMutableDictionary dictionaryWithDictionary:userInfo];
    [cellUserInfo setValue:[NSNumber numberWithInteger:RNTrackingCancelButton] forKey:trackingTypeKey];
    area = [[NSTrackingArea alloc] initWithRect:[self cancelButtonRectForBounds:cellFrame] options:options owner:controlView userInfo:cellUserInfo];
    [controlView addTrackingArea:area];
}

- (void)mouseEntered:(NSEvent *)event {
    NSDictionary *userInfo = [event userData];
    RNTrackingType trackingType = [[userInfo valueForKey:trackingTypeKey] integerValue];
    [self setMouseIsHoveringOverTitle:(trackingType == RNTrackingTitle)];
    if (trackingType == RNTrackingCancelButton)
        [[self cancelButton] mouseEntered:event];
    [(NSControl *)[self controlView] updateCell:self];
}

- (void)mouseExited:(NSEvent *)event {
    [self setMouseIsHoveringOverTitle:NO];
    NSDictionary *userInfo = [event userData];
    RNTrackingType trackingType = [[userInfo valueForKey:trackingTypeKey] integerValue];
    if (trackingType == RNTrackingCancelButton)
        [[self cancelButton] mouseExited:event];
    [(NSControl *)[self controlView] updateCell:self];
}

- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView {
    NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil];
    if ([controlView mouse:point inRect:[self titleRectForBounds:cellFrame]] || 
        [controlView mouse:point inRect:[self cancelButtonRectForBounds:cellFrame]] ||
        [controlView mouse:point inRect:[self stepperRectForBounds:cellFrame]]) {
        return NSCellHitContentArea | NSCellHitTrackableArea;        
    }
    return [super hitTestForEvent:event inRect:cellFrame ofView:controlView];
}

- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp {
    NSRect titleRect = [self titleRectForBounds:cellFrame];
    NSRect cancelRect = [self cancelButtonRectForBounds:cellFrame];
    NSRect stepperRect = [self stepperRectForBounds:cellFrame];
    NSPoint eventPoint = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
    if ([controlView mouse:eventPoint inRect:cancelRect]) {
        [[self cancelButton] setControlView:controlView];
        return [[self cancelButton] trackMouse:theEvent inRect:cancelRect ofView:controlView untilMouseUp:untilMouseUp];
    }
    else if ([controlView mouse:eventPoint inRect:stepperRect]) {
        [[self stepperCell] setIntegerValue:[[self count] integerValue]];
        BOOL returnValue = [[self stepperCell] trackMouse:theEvent inRect:stepperRect ofView:controlView untilMouseUp:YES];
        NSNumber *newCount = [NSNumber numberWithInteger:[[self stepperCell] integerValue]];
        [(RNListItem *)[self representedObject] setCount:newCount];
        return returnValue;        
    }
    else if (![controlView mouse:eventPoint inRect:titleRect]) {
        return [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
    }
    while ([theEvent type] != NSLeftMouseUp) {
        eventPoint = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
        [self setMouseIsHoveringOverTitle:[controlView mouse:eventPoint inRect:titleRect]];
        if ([theEvent type] == NSMouseEntered || [theEvent type] == NSMouseExited) 
            [NSApp sendEvent:theEvent];
        theEvent = [[controlView window] nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask | NSMouseEnteredMask | NSMouseExitedMask)];
    }

    if ([self mouseIsHoveringOverTitle]) {
        [NSApp sendAction:[self action] to:[self target] from:self];
    }
    [self setMouseIsHoveringOverTitle:NO];
    [(NSControl *)[self controlView] updateCell:self];
    return YES;
}

@end
